#pragma once

#include <iostream>
#include <mutex>
#include <assert.h>

#include "util.hpp"

class user_table
{
private:
    MYSQL *_mysql;
    std::mutex _mutex;

public:
    user_table(const std::string &host, const std::string &user, const std::string &password, const std::string &name, uint16_t port = 3306)
    {
        _mysql = ns_util::mysql_util::mysql_creat(host, user, password, name, port);
        assert(_mysql != nullptr);
    }

    ~user_table()
    {
        if (_mysql != nullptr)
        {
            ns_util::mysql_util::mysql_release(_mysql);
        }
        return;
    }

    // 注册新用户
    bool insert(Json::Value &user)
    {
#define INSERT_USER "insert into user values(null, '%s', MD5('%s'),1000,0,0);"

        char sql[1024] = {0};
        sprintf(sql, INSERT_USER, user["username"].asCString(), user["password"].asCString());

        bool ret = ns_util::mysql_util::mysql_exec(_mysql, sql);

        if (ret == false)
        {
            LOG_INF("insert user info error");
            return false;
        }

        return true;
    }

    /// 登录验证
    bool login(Json::Value &user)
    {
        // 获取用户信息并进行比对

#define LOGIN_USER "select id,score,total_count,win_count from user where username='%s' and password=MD5('%s'); "

        char sql[1024] = {0};

        sprintf(sql, LOGIN_USER, user["username"].asCString(), user["password"].asCString());

        MYSQL_RES *res = NULL;
        {
            std::unique_lock<std::mutex> lock(_mutex);

            // 执行语句
            bool ret = ns_util::mysql_util::mysql_exec(_mysql, sql);
            if (ret == false)
            {
                LOG_INF("select user info error");
                return false;
            }

            // 保存执行结果到本地
            res = mysql_store_result(_mysql);
            if (res == NULL)
            {
                LOG_INF("have no login user info");
                return false;
            }
        }

        // 获取执行结果的条数
        int row_num = mysql_num_rows(res);
        if (row_num != 1)
        {
            LOG_INF("info number error");
            return false;
        }

        MYSQL_ROW row = mysql_fetch_row(res);

        user["id"] = (Json::UInt64)std::stol(row[0]);
        user["score"] = (Json::UInt64)std::stol(row[1]);
        user["total_count"] = std::stoi(row[2]);
        user["win_count"] = std::stoi(row[3]);

        mysql_free_result(res);

        return true;
    }

    // 通过用户名获取用户信息
    bool select_by_name(const std::string user_name, Json::Value &user_info)
    {
#define USER_BY_NAME "select id,score,total_count,win_count from user where username='%s'; "

        char sql[1024] = {0};

        sprintf(sql, USER_BY_NAME, user_name.c_str());

        MYSQL_RES *res = NULL;

        {
            std::unique_lock<std::mutex> lock(_mutex);
            bool ret = ns_util::mysql_util::mysql_exec(_mysql, sql);
            if (ret == false)
            {
                LOG_INF("select user info by username error");
                return false;
            }

            res = mysql_store_result(_mysql);
            if (res == NULL)
            {
                LOG_INF("have no login user info");
                return false;
            }
        }

        // 获取执行结果的条数
        int row_num = mysql_num_rows(res);
        if (row_num != 1)
        {
            LOG_INF("info number error");
            return false;
        }

        // 类似于迭代器的一个遍历函数
        MYSQL_ROW row = mysql_fetch_row(res);

        user_info["id"] = (Json::UInt64)std::stol(row[0]);
        user_info["username"] = user_name;
        user_info["score"] = (Json::UInt64)std::stol(row[1]);
        user_info["total_count"] = std::stoi(row[2]);
        user_info["win_count"] = std::stoi(row[3]);
        

        mysql_free_result(res);
        return true;
    }

    // 通过用户id获取用户信息
    bool select_by_id(const int user_id, Json::Value &user_info)
    {
#define USER_BY_ID "select username,score,total_count,win_count from user where id='%d';"
        char sql[1024] = {0};

        sprintf(sql, USER_BY_ID, user_id);

        MYSQL_RES *res = NULL;

        {
            std::unique_lock<std::mutex> lock(_mutex);
            bool ret = ns_util::mysql_util::mysql_exec(_mysql, sql);
            if (ret == false)
            {
                LOG_INF("select user info by id error");
                return false;
            }

            res = mysql_store_result(_mysql);
            if (res == NULL)
            {
                LOG_INF("have no login user info");
                return false;
            }
        }

        // 获取执行结果的条数
        int row_num = mysql_num_rows(res);
        if (row_num != 1)
        {
            LOG_INF("info number error");
            return false;
        }

        // 类似于迭代器的一个遍历函数
        MYSQL_ROW row = mysql_fetch_row(res);

        user_info["id"] = (Json::UInt64)user_id;
        user_info["username"] = row[0];

        user_info["score"] = (Json::UInt64)std::stol(row[1]);
        user_info["total_count"] = std::stoi(row[2]);
        user_info["win_count"] = std::stoi(row[3]);

        mysql_free_result(res);
        return true;
    }

    // 胜利时天梯分数增加
    bool win(int id)
    {
#define USER_WIN "update user set score=score+30, total_count=total_count+1, win_count=win_count+1 where id='%d';"
        char sql[1024];
        sprintf(sql, USER_WIN, id);

        bool ret = ns_util::mysql_util::mysql_exec(_mysql, sql);

        if (ret == false)
        {
            LOG_INF("update win user error");
            return false;
        }

        return true;
    }

    // 失败时天梯分数减少
    bool lose(int id)
    {
#define USER_LOSE "update user set score=score-30, total_count=total_count+1 where id='%d';"
        char sql[1024];
        sprintf(sql, USER_LOSE, id);

        bool ret = ns_util::mysql_util::mysql_exec(_mysql, sql);

        if (ret == false)
        {
            LOG_INF("update lose user error");
            return false;
        }

        return true;
    }
};